﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Common.Encrypt
{
    /// <summary>
    /// SHA1哈希算法
    /// <remarks>
    /// <![CDATA[
    /// 安全哈希算法（Secure Hash Algorithm）主要适用于数字签名标准 （Digital Signature Standard DSS）里面定义的数字签名算法（Digital Signature Algorithm DSA）。
    /// 对于长度小于2^64位的消息，SHA1会产生一个160位的消息摘要。当接收到消息的时候，这个消息摘要可以用来验证数据的完整性。在传输的过程中，数据很可能会发生变化，那么这时候就会产生不同的消息摘要。 
    /// SHA1有如下特性：
    ///   不可以从消息摘要中复原信息；
    ///   两个不同的消息不会产生同样的消息摘要。
    /// ]]>
    /// </remarks>
    /// </summary>
    public sealed class SHA1Provider
    {
        /// <summary>
        /// SHA1签名，默认UTF-8编码
        /// </summary>
        /// <param name="str">需要签名的字符串</param>
        /// <example>
        /// <code>
        ///        private void EncodeDemo()
        ///        {
        ///            //内容
        ///            string srt = @"这是内容";
        ///
        ///            //对内容SHA1
        ///            string md5 = SHA1Provide.Encode(srt);
        ///            
        ///            //md5的值为：C33A2BF7B5F08CE639F517EE0D70EECDE1F7BFF7
        ///        }
        /// </code>
        /// </example>
        /// <returns>返回一个string的SHA1值</returns>
        public static string Encode(string str)
        {
            return Encode(str, Encoding.UTF8);
        }

        /// <summary>
        /// SHA1签名，默认UTF-8编码
        /// </summary>
        /// <param name="str">需要签名的字符串</param>
        /// <param name="encoding">编码类型</param>
        /// <example>
        /// <code>
        /// <![CDATA[
        ///  private void EncodeDemo()
        ///  {
        ///      //内容     
        ///      string srt = @"这是内容";      
        ///       
        ///      //对内容SHA1      
        ///      string md5 = SHA1Provide.Encode(srt,Encoding.UTF8); 
        ///      
        ///      //md5的值为：C33A2BF7B5F08CE639F517EE0D70EECDE1F7BFF7
        ///  }      
        ///  ]]>      
        /// </code>
        /// </example>
        /// <returns>返回一个string的SHA1值</returns>
        public static string Encode(string str, Encoding encoding)
        {
            byte[] bytes = encoding.GetBytes(str);

            SHA1 provider = new SHA1CryptoServiceProvider();
            byte[] shaiBytes = provider.ComputeHash(bytes);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < shaiBytes.Length; i++)
            {
                sb.Append(shaiBytes[i].ToString("x2"));
            }
            return sb.ToString().ToUpper();

        }

        /// <summary>
        /// 文件SHA1签名
        /// </summary>
        /// <param name="path">文件物理路径</param>
        /// <example>
        /// <code>
        /// <![CDATA[
        ///         private void EncodeFileDemo()
        ///        {
        ///            //文件路径
        ///            string path = @"D:\File\text.txt";
        ///
        ///            //对文件SHA1
        ///            string sha1 = SHA1Provide.EncodeFile(path);
        ///        }
        /// ]]>
        /// </code>
        /// </example>
        /// <returns>返回path指定的文件SHA1值</returns>
        public static string EncodeFile(string path)
        {
            FileStream file = new FileStream(path, FileMode.Open);
            return EncodeFile(file);
        }

        /// <summary>
        /// 文件SHA1签名
        /// </summary>
        /// <param name="stream">文件流</param>
        /// <example>
        /// <code>
        /// <![CDATA[
        ///        private void EncodeFileDemo()
        ///        {
        ///            //文件路径
        ///            string path = @"D:\File\text.txt";
        ///            
        ///            //获取文件流
        ///            FileStream fileStream = new FileStream(path, FileMode.Open);
        ///            
        ///            //对文件流SHA1
        ///            string sha1 = SHA1Provide.EncodeFile(fileStream);
        ///        }
        ///  ]]>
        /// </code>
        /// </example>
        /// <returns>返回path指定的文件SHA1值</returns>
        /// <returns></returns>
        public static string EncodeFile(Stream stream)
        {
            System.Security.Cryptography.SHA1 provider = new System.Security.Cryptography.SHA1CryptoServiceProvider();
            byte[] retVal = provider.ComputeHash(stream);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
            {
                sb.Append(retVal[i].ToString("x2"));
            }
            return sb.ToString().ToUpper();
        }
    }
}
